/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cargarDatos;

import java.awt.Point;
import java.nio.Buffer;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;


/**
 *
 * @author civilian
 */
public class BufferInsertMatriculas{

    static final int CAPACIDAD_DEFAULT=50;//topcoder xP
    int _capacidad;
    int _posicion;
    String comiensoInsert;
    StringBuilder comando;
    Statement st;
    
    // debugear la capacidad// ta bien
    protected BufferInsertMatriculas(Statement st,String comiensoInsert, int comasAntesLocacion) {
        _capacidad=CAPACIDAD_DEFAULT;
        _posicion=0;//cuenta la cantidad de datos que se metieron
        this.st=st;
        this.comiensoInsert=comiensoInsert;
        comando=new StringBuilder();
        comando.append(comiensoInsert);
        
        matriculasLocacion=new HashMap<MatriculaLocacionPK, Hechos>();
    }
    
    boolean append(String cad, int locacion, int fecha, int hora,int programa, 
                                int asignatura, int accion,String sexo) throws SQLException{
        try{
            if(_posicion!=0)
            comando.append(" ,\n");
    //        dbg(cad);
            _posicion++;
            comando.append(cad);
            
            contarAgregado(locacion,fecha,hora,accion,programa,asignatura, sexo);
            
            if(_posicion==_capacidad){
                st.executeUpdate(comando.toString());
                actualizarAgregado();
                reiniciar();
                return true;
            }
        }
        catch(SQLException e){
            esepcion(e);
        }
        
        return false;
    }
    
    void flush() throws SQLException{
        try{
            if(_posicion==0){
                reiniciar();
                return;
            }
            st.executeUpdate(comando.toString());
            actualizarAgregado();
            
            reiniciar();
        }
        catch(SQLException e){
            esepcion(e);
        }
    }

    private void esepcion(SQLException e) throws SQLException{
            if(e.getSQLState().equals("23505"))//no toy violando una unique constraint
            {
                
                System.err.println("restriccion de unicidad violada");
                
                comando.delete(0, comiensoInsert.length());
                
                StringTokenizer tk=new StringTokenizer(comando.toString(), "\n");
                while (tk.hasMoreTokens()) {
                    try {
                        String comando=comiensoInsert+" "+tk.nextToken().replace(") ,",")");
//                        dbg(comando);
                        st.executeUpdate(comando);
                    } catch (SQLException ex) {
                        if(ex.getSQLState().equals("23505"))
                        continue;
                        else throw ex;
                    }
                    
                }
                reiniciar();
            }
            else
                throw e;
    }
    
    private void reiniciar(){
            comando=new StringBuilder(comiensoInsert);//reinicio comando;
            _posicion=0;
    }
    
    @Override
    public String toString() {
        return "BufferInsert{" + ", _posicion=" + _posicion +  ", comando=" + comando + ", st=" + st + '}';
    }

    static  void dbg(Object...o) {
        System.out.println(Arrays.deepToString(o));
    }

    private HashMap<MatriculaLocacionPK, Hechos> matriculasLocacion;
    //x=matricula, y=cancelacion
    
    private void contarAgregado(int locacion,int fecha,int hora, int accion,int programa,int asignatura,
                            String sexo) {
        MatriculaLocacionPK obj=new MatriculaLocacionPK(locacion,fecha,hora,programa,asignatura);
        Hechos actual= matriculasLocacion.get(obj);
        actual=(actual==null)?
                new Hechos():actual;
        
        if(accion==CargaDatos.MATRICULAR|| accion==CargaDatos.REACTIVAR)
            actual.numeroCursosMatriculados++;
        else if(accion==CargaDatos.CANCELAR)
            actual.numeroCursosCancelados++;
        
        contarSegunSexo(actual, sexo);
        matriculasLocacion.put(obj, actual);
    }
    
    static public String[] sexos=new String[]{"Femenino","Masculino","Ambos"};
    
    private void contarSegunSexo(Hechos actual, String sexo) {
        if(sexo.equals("Femenino")){
            actual.MatriculaMujeres++;
        }else if(sexo.equals("Masculino")){
            actual.MatriculaHombres++;
        }else if(sexo.equals("Ambos")){
            contarSegunSexo(actual, sexos[Math.round((float)Math.random())]);
        }        
        return;
    }

    private boolean actualizarAgregado() throws SQLException {
        for (Map.Entry<MatriculaLocacionPK, Hechos> locacion: matriculasLocacion.entrySet() ){
            MatriculaLocacionPK obj=locacion.getKey();
            String select=String.format("SELECT numeroCursosMatriculados, numeroCursosCancelados, matriculaMujeres, matriculaHombres, "
                    + "locacion,fecha,hora ,programa,asignatura "
                    + "FROM matriculaxlocacion WHERE locacion=%d AND fecha=%d AND hora=%d AND programa=%d AND asignatura=%d " 
                                                            ,obj.locacion,obj.fecha,obj.hora,obj.programa,obj.asignatura);
//            dbg(select);
            ResultSet rs=st.executeQuery(select);
            
            Hechos cantidades=locacion.getValue();
            int numeroMatriculados=cantidades.numeroCursosMatriculados;
            int numeroCancelados=cantidades.numeroCursosCancelados;
            int matriculasMujeres=cantidades.MatriculaMujeres;
            int matriculasHombre=cantidades.MatriculaHombres;
            int total;
            if(rs.next()){
                numeroMatriculados+=rs.getInt(1);
                numeroCancelados+=rs.getInt(2);
                total=numeroCancelados+numeroMatriculados;
                
                matriculasHombre+=rs.getInt(3);
                matriculasMujeres+=rs.getInt(4);
                String selectUP=String.format("UPDATE matriculaxlocacion SET numeroCursosMatriculados= %d, numeroCursosCancelados=%d, "
                                + "totalMatricula=%d, matriculaMujeres=%d, matriculaHombres=%d "
                                + "WHERE locacion=%d AND fecha=%d AND hora=%d AND programa=%d AND asignatura=%d",
                                numeroMatriculados, numeroCancelados, total, matriculasMujeres, matriculasMujeres, 
                                                                        obj.locacion,obj.fecha,obj.hora,obj.programa,obj.asignatura);
//                dbg(selectUP);
                st.executeUpdate(selectUP);
//                dbg(numeroMatriculados, numeroCancelados, total, obj.locacion,obj.fecha,obj.hora);
            }
            else {
                total=numeroCancelados+numeroMatriculados;
                st.executeUpdate(
                        String.format("INSERT INTO matriculaxlocacion VALUES (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d) "
                                                                , obj.locacion, obj.fecha, obj.hora, obj.programa, obj.asignatura,
                                                                 total,numeroMatriculados, numeroCancelados,matriculasMujeres,
                                                                         matriculasHombre));
            }
        }
        matriculasLocacion.clear();
        return true;
    }
    
}
class MatriculaLocacionPK{
    int locacion, fecha,hora,programa,asignatura;

    public MatriculaLocacionPK(int locacion, int fecha, int hora, int programa, int asignatura) {
        this.locacion = locacion;
        this.fecha = fecha;
        this.hora = hora;
        this.programa = programa;
        this.asignatura = asignatura;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final MatriculaLocacionPK other = (MatriculaLocacionPK) obj;
        if (this.locacion != other.locacion) {
            return false;
        }
        if (this.fecha != other.fecha) {
            return false;
        }
        if (this.hora != other.hora) {
            return false;
        }
        if (this.programa != other.programa) {
            return false;
        }
        if (this.asignatura != other.asignatura) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 79 * hash + this.locacion;
        hash = 79 * hash + this.fecha;
        hash = 79 * hash + this.hora;
        hash = 79 * hash + this.programa;
        hash = 79 * hash + this.asignatura;
        return hash;
    }
}

class Hechos{
    int MatriculaHombres, MatriculaMujeres, numeroCursosMatriculados ,
    numeroCursosCancelados;
}
